package cn.charlab.boot.obs;

import cn.charlab.boot.exception.OsException;
import cn.charlab.boot.obs.properties.ObsProperties;
import cn.charlab.boot.template.StorageTemplate;
import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.model.DeleteObjectResult;
import com.obs.services.model.HeaderResponse;
import com.obs.services.model.ObjectMetadata;
import com.obs.services.model.ObsObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;

@Slf4j
public class ObsTemplate implements StorageTemplate {

    private ObsProperties obsProperties;

    private ObsClient obsClient;

    public ObsTemplate(ObsProperties obsProperties){
        this.obsProperties = obsProperties;
    }



    private void init(){
        if (!obsEnable()){
            return;
        }
        ObsConfiguration configuration = new ObsConfiguration();
        configuration.setConnectionTimeout(obsProperties.getConnectionTimeout());
        configuration.setSocketTimeout(obsProperties.getSocketTimeout());
        obsClient = new ObsClient(obsProperties.getAccessKey(),obsProperties.getSecretKey(),
                obsProperties.getSecurityToken(),obsProperties.getEndPoint());
    }

    private boolean obsEnable(){
        if (obsProperties == null || !StringUtils.hasLength(obsProperties.getEndPoint())){
            return false;
        }
        return true;
    }

    public ObsProperties getObsProperties() {
        return obsProperties;
    }

    public ObsClient getObsClient() {
        return obsClient;
    }

    @Override
    public void destroy() throws Exception {
        obsClient.close();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    @Override
    public boolean createBucket(String bucket) throws OsException {
        try{
            obsClient.createBucket(bucket);
        }catch (Exception e){
            throw new OsException(e);
        }
        return true;
    }

    @Override
    public boolean deleteBucket(String bucket) throws OsException {
        HeaderResponse response = obsClient.deleteBucket(bucket);
        return response.getStatusCode() == 200;
    }

    @Override
    public boolean bucketExists(String bucket) throws OsException {
        return obsClient.getBucketLocation(bucket) != null;
    }

    @Override
    public void putObject(String bucket, String key, InputStream input) throws OsException {
        try {
            obsClient.putObject(bucket,key,input);
        } catch (Exception e){
            throw new OsException(e);
        }
    }

    @Override
    public void putObject(String bucket, String key, InputStream input, Map<String, Object> headers) throws OsException {
        try {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setResponseHeaders(headers);
            obsClient.putObject(bucket,key,input,metadata);
        } catch (Exception e){
            throw new OsException(e);
        }
    }

    @Override
    public InputStream getObject(String bucket, String key) throws OsException {
        ObsObject obsObject = obsClient.getObject(bucket,key);
        return obsObject.getObjectContent();
    }

    @Override
    public void getObject(String bucket, String key, OutputStream out) throws OsException {
        ObsObject o = obsClient.getObject(bucket, key);
        try (InputStream in = o.getObjectContent()) {
            IOUtils.copyLarge(in, out);
        } catch (Exception e) {
            throw new OsException(e);
        }
    }

    @Override
    public boolean deleteObject(String bucket, String key) throws OsException {
        DeleteObjectResult deleteObjectResult = obsClient.deleteObject(bucket,key);
        return deleteObjectResult.getStatusCode() == 200;
    }

    @Override
    public boolean existObject(String bucket, String key) throws OsException {
        ObsObject obj = obsClient.getObject(bucket,key);
        return obj != null;
    }
}
